/**
 * Copyright 2013 Net355 Co,.Ltd. 
 * All rights reserved.
 *
 * "SyncHelper.java is for what: "
 * 
 * Create by Ray at Dec 15, 2013 9:19:07 PM.
 * Ray [email:rayinhangzhou@126.com]
 * 
 * Revision History
 *
 * Date            Programmer                   Notes
 * ---------    ---------------------  -----------------------------------
 * Dec 15, 2013            Ray                       initial
 **/


package com.net355.eblog.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.evernote.auth.EvernoteAuth;
import com.evernote.auth.EvernoteService;
import com.evernote.clients.ClientFactory;
import com.evernote.clients.NoteStoreClient;
import com.evernote.clients.UserStoreClient;
import com.evernote.edam.notestore.SyncChunk;
import com.evernote.edam.notestore.SyncChunkFilter;
import com.evernote.edam.type.Note;
import com.evernote.edam.type.Notebook;
import com.evernote.edam.type.Tag;
import com.net355.eblog.models.EbChat;
import com.net355.eblog.models.EbNote;
import com.net355.eblog.models.EbNotebook;
import com.net355.eblog.models.EbTag;



public class SyncHelper {
	private static Log LOG = LogFactory.getLog(SyncHelper.class);
	private static Timer TIMER_SYNC;
	private static int LAST_SYNC_HOUR = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);

	private static EvernoteAuth evernoteAuth;
	private static ClientFactory factory;
	private static UserStoreClient userStore;
	private static NoteStoreClient noteStore;
	private static SyncChunkFilter SYNC_CHUNK_FILTER = new SyncChunkFilter();
	
	
	/**
	 * 每隔1小时同步更新
	 */
	public static void initSyncWithEvernote() {
		SYNC_CHUNK_FILTER.setIncludeNotes(true);
//		SYNC_CHUNK_FILTER.setIncludeNoteResources(true);
//		SYNC_CHUNK_FILTER.setIncludeNoteAttributes(true);
		SYNC_CHUNK_FILTER.setIncludeNotebooks(true);
//		SYNC_CHUNK_FILTER.setIncludeTags(true);
//		SYNC_CHUNK_FILTER.setIncludeResources(true);
		TIMER_SYNC = new Timer();
		TIMER_SYNC.schedule(new TimerTask() {
			@Override
			public void run() {
				try {
					int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
					CacheHelper.set_cache(GlobalParams.CACHE_NAME_COUNT_CHAT, GlobalParams.COUNT_CHAT.get());
					CacheHelper.set_cache(GlobalParams.CACHE_NAME_COUNT_SEARCH, GlobalParams.COUNT_SEARCH.get());
					CacheHelper.set_cache(GlobalParams.CACHE_NAME_COUNT_UPDATE, GlobalParams.COUNT_UPDATE.get());
					CacheHelper.set_cache(GlobalParams.CACHE_NAME_COUNT_VIEW, GlobalParams.COUNT_VIEW.get());
					if(hour!=LAST_SYNC_HOUR) {
						//每周一凌晨清空游戏排名
						if(Calendar.getInstance().get(Calendar.DAY_OF_WEEK)==1 && hour==0) {
							CacheHelper.set_cache(GlobalParams.CACHE_NAME_LIST_GAME_SCORE, new ArrayList<>());
						}
						LAST_SYNC_HOUR = hour;
						evernoteAuth = new EvernoteAuth(EvernoteService.PRODUCTION, GlobalParams.AUTH_TOKEN);
						factory = new ClientFactory(evernoteAuth);
						userStore = factory.createUserStoreClient();
						noteStore = factory.createNoteStoreClient();
						boolean versionOk = userStore.checkVersion("Evernote EDAMDemo (Java)", com.evernote.edam.userstore.Constants.EDAM_VERSION_MAJOR,
								com.evernote.edam.userstore.Constants.EDAM_VERSION_MINOR);
						if (!versionOk) {
							LOG.error("Incompatible Evernote client protocol version--->>>");
						} else {
							NoteStoreClient noteStore = factory.createNoteStoreClient();
							SyncChunk chunk = noteStore.getFilteredSyncChunk(GlobalParams.COUNT_UPDATE.get(), Integer.MAX_VALUE, SYNC_CHUNK_FILTER);
							syncChunkContent(chunk);
							GlobalParams.COUNT_UPDATE = new AtomicInteger(chunk.getUpdateCount());
							CacheHelper.set_cache(GlobalParams.CACHE_NAME_COUNT_UPDATE, chunk.getUpdateCount());
							System.out.println("ray_print-syncWithEvernote finished-->");
							System.out.println("ray_print-sign-->"+GlobalParams.COUNT_UPDATE.get());
//							System.exit(0);
						}
						//备份缓存文件
						File cacheDir = new File(System.getProperty("ehcache.disk.store.dir"));
						if(cacheDir.isDirectory()) {
							File[] files = cacheDir.listFiles();
							FileInputStream fin = null;
							FileOutputStream fout = null;
							for (int i = 0; i < files.length; i++) {
								if(files[i].isFile() && (files[i].getName().contains(".index") || files[i].getName().contains(".data"))) {
									fin = new FileInputStream(files[i]);
									fout = new FileOutputStream(cacheDir.getAbsolutePath()+"/bk/"+files[i].getName());
									// 获取输入输出通道  
							        FileChannel fcin = fin.getChannel();  
							        FileChannel fcout = fout.getChannel();  
							        // 创建缓冲区  
							        ByteBuffer buffer = ByteBuffer.allocate(2048);
							        while (true) {  
							            buffer.clear();  
							            int r = fcin.read(buffer);  
							            if (r == -1) {  
							                break;  
							            }  
							            buffer.flip();  
							            fcout.write(buffer);  
							        }  
								}
							}
						}
					}
				} catch (Exception e) {
					LOG.error("syncWithEvernote error--->>>", e);
				}
			}
		}, 3000, 3*60*1000);
	}
	
	@SuppressWarnings("unchecked")
	private static void syncChunkContent(SyncChunk chunk){
		try {
			if(chunk.getNotebooksSize()>0) {	//	新增或修改notebooks
				List<String> cacheNotebookList = (List<String>)CacheHelper.get_cache(GlobalParams.CACHE_NAME_LIST_NOTEBOOK);
				List<Notebook> notebooks = chunk.getNotebooks();
				for (Notebook notebook : notebooks) {
					if(!GlobalParams.NOTEBOOK_FILTER.containsKey(notebook.getGuid())) {
						continue;
					}
					System.out.println("notebook-->"+notebook);
					EbNotebook _notebook = (EbNotebook)CacheHelper.get_cache(notebook.getGuid());
					if(_notebook!=null) {
						_notebook.setName(notebook.getName());
						_notebook.setUpdateTime(notebook.getServiceUpdated());
						cacheNotebookList.remove(notebook.getGuid());
					} else {
						_notebook = new EbNotebook();
						_notebook.setGuid(notebook.getGuid());
						_notebook.setName(notebook.getName());
						_notebook.setCreateTime(notebook.getServiceCreated());
						_notebook.setUpdateTime(notebook.getServiceUpdated());
					}
					CacheHelper.set_cache(notebook.getGuid(), _notebook);
					cacheNotebookList.add(notebook.getGuid());
				}
				CacheHelper.set_cache(GlobalParams.CACHE_NAME_LIST_NOTEBOOK, cacheNotebookList);
			}
			if(chunk.getNotesSize()>0) {	//	新增或修改notebooks
				List<Note> notes = chunk.getNotes();
				for (Note note : notes) {
					if(!GlobalParams.NOTEBOOK_FILTER.containsKey(note.getNotebookGuid())) {
						continue;
					}
					System.out.println(DateToolkit.formatDate("HH:mm:ss")+"_deal-->"+note.getTitle());
					EbNote note_old = (EbNote)CacheHelper.get_cache(note.getGuid());
					if(note_old!=null) {	//	update note
						if(!note_old.getNotebookGuid().equals(note.getNotebookGuid())) {
							EbNotebook eNotebook_old = (EbNotebook)CacheHelper.get_cache(note_old.getNotebookGuid());
							eNotebook_old.getNotes().remove(note.getGuid());
							eNotebook_old.setUpdateTime(note.getUpdated());
							CacheHelper.set_cache(eNotebook_old.getGuid(), eNotebook_old); 
							EbNotebook eNotebook = (EbNotebook)CacheHelper.get_cache(note.getNotebookGuid());
							eNotebook.getNotes().add(note.getGuid());
							eNotebook.setUpdateTime(note.getUpdated());
							CacheHelper.set_cache(eNotebook.getGuid(), eNotebook); 
						}
						if(note.getDeleted()==0) {	//update note object
							for (int i = 0; i < note_old.getTags().size(); i++) {	//update old tags with remove note
								String tagGuid = note_old.getTags().get(i);
								EbTag _tag = (EbTag)CacheHelper.get_cache(tagGuid);
								_tag.getNotes().remove(note.getGuid());
								CacheHelper.set_cache(tagGuid, _tag);
							}
							List<String> cacheTagList = (List<String>)CacheHelper.get_cache(GlobalParams.CACHE_NAME_LIST_TAG);
							for (int i = 0; i < note.getTagGuidsSize(); i++) {	//update new tags with add note
								String tagGuid = note.getTagGuids().get(i);
								EbTag _tag = (EbTag)CacheHelper.get_cache(tagGuid);
								if(_tag==null) {
									Tag tag = noteStore.getTag(tagGuid);
									Thread.sleep(500);
									_tag = new EbTag();
									_tag.setGuid(tagGuid);
									_tag.setName(tag.getName());
								} else {
									cacheTagList.remove(tagGuid);
								}
								_tag.getNotes().add(note.getGuid());
								_tag.setUpdateTime(note.getUpdated());
								CacheHelper.set_cache(tagGuid, _tag);
								cacheTagList.add(tagGuid);
							}
							if(note.getTagGuidsSize()>0) {	//check if has tag changed
								CacheHelper.set_cache(GlobalParams.CACHE_NAME_LIST_TAG, cacheTagList);
							}
							note_old.setTags(note.getTagGuids());
							note_old.setTitle(note.getTitle());
							note_old.setUpdateTime(note.getUpdated());
							if(StringUtil.bytesToHex(note.getContentHash()).equals(note_old.getContentHash())) {
								CacheHelper.set_cache(note_old.getGuid(), note_old);
							} else {
								updateNoteContentCache(note_old);
							}
							List<String> cacheNoteList = (List<String>)CacheHelper.get_cache(GlobalParams.CACHE_NAME_LIST_NOTE);
							cacheNoteList.remove(note.getGuid());
							cacheNoteList.add(note.getGuid());
							CacheHelper.set_cache(GlobalParams.CACHE_NAME_LIST_NOTE, cacheNoteList);
						} else {	//	remove note object
							List<String> cacheTagList = (List<String>)CacheHelper.get_cache(GlobalParams.CACHE_NAME_LIST_TAG);
							for (int i = 0; i < note.getTagGuidsSize(); i++) {
								String tagGuid = note.getTagGuids().get(i);
								EbTag tag = (EbTag)CacheHelper.get_cache(tagGuid);
								tag.getNotes().remove(note.getGuid());
								CacheHelper.set_cache(tagGuid, tag);
								cacheTagList.remove(tagGuid);
							}
							if(note.getTagGuidsSize()>0) {
								CacheHelper.set_cache(GlobalParams.CACHE_NAME_LIST_TAG, cacheTagList);
							}
							EbNotebook notebook = (EbNotebook)CacheHelper.get_cache(note.getNotebookGuid());
							notebook.getNotes().remove(note.getGuid());
							CacheHelper.set_cache(notebook.getGuid(), notebook);
							CacheHelper.remove_cache(note.getGuid());
							CacheHelper.remove_cache_text(note.getGuid());
							CacheHelper.remove_cache_html(note.getGuid());
							List<String> cacheNoteList = (List<String>)CacheHelper.get_cache(GlobalParams.CACHE_NAME_LIST_NOTE);
							cacheNoteList.remove(note.getGuid());
							CacheHelper.set_cache(GlobalParams.CACHE_NAME_LIST_NOTE, cacheNoteList);
						}
					} else {	//	add new note
						if(note.getDeleted()!=0) {	//skip removed note object
							continue;
						}
						List<String> cacheTagList = (List<String>)CacheHelper.get_cache(GlobalParams.CACHE_NAME_LIST_TAG);
						for (int i = 0; i < note.getTagGuidsSize(); i++) {	//update new tags with add note
							String tagGuid = note.getTagGuids().get(i);
							EbTag _tag = (EbTag)CacheHelper.get_cache(tagGuid);
							if(_tag==null) {
								Tag tag = noteStore.getTag(tagGuid);
								Thread.sleep(500);
								_tag = new EbTag();
								_tag.setGuid(tagGuid);
								_tag.setName(tag.getName());
							} else {
								cacheTagList.remove(tagGuid);
							}
							_tag.getNotes().add(note.getGuid());
							_tag.setUpdateTime(note.getUpdated());
							CacheHelper.set_cache(tagGuid, _tag);
							cacheTagList.add(tagGuid);
						}
						if(note.getTagGuidsSize()>0) {
							CacheHelper.set_cache(GlobalParams.CACHE_NAME_LIST_TAG, cacheTagList);
						}
						EbNotebook eNotebook = (EbNotebook)CacheHelper.get_cache(note.getNotebookGuid());
						eNotebook.getNotes().add(note.getGuid());
						eNotebook.setUpdateTime(note.getUpdated());
						CacheHelper.set_cache(eNotebook.getGuid(), eNotebook); 
						List<String> cacheNotebookList = (List<String>)CacheHelper.get_cache(GlobalParams.CACHE_NAME_LIST_NOTEBOOK);
						cacheNotebookList.remove(note.getNotebookGuid());
						cacheNotebookList.add(note.getNotebookGuid());
						CacheHelper.set_cache(GlobalParams.CACHE_NAME_LIST_NOTEBOOK, cacheNotebookList);
						EbNote eNote = new EbNote();
						eNote.setGuid(note.getGuid());
						eNote.setTags(note.getTagGuids());
						eNote.setNotebookGuid(note.getNotebookGuid());
						eNote.setTitle(note.getTitle());
						eNote.setUpdateTime(note.getUpdated());
						eNote.setContentHash("none");
						updateNoteContentCache(eNote);
						List<String> cacheNoteList = (List<String>)CacheHelper.get_cache(GlobalParams.CACHE_NAME_LIST_NOTE);
						cacheNoteList.add(note.getGuid());
						CacheHelper.set_cache(GlobalParams.CACHE_NAME_LIST_NOTE, cacheNoteList);
						List<?> chats = (List<?>) CacheHelper.get_cache(note.getGuid()+GlobalParams.CACHE_NAME_LIST_NOTE_COMMENT);
						if(chats==null) {
							CacheHelper.set_cache(note.getGuid()+GlobalParams.CACHE_NAME_LIST_NOTE_COMMENT, new ArrayList<EbChat>());
						}
					}
				}
			}
		} catch (Exception e) {
			LOG.error("syncChunkContent error--->>>", e);
		}
	};
	
	private static void updateNoteContentCache(EbNote note) throws Exception {
		try {
			Note detailNote = noteStore.getNote(note.getGuid(), true, false, false, false);
			note.setContentHash(StringUtil.bytesToHex(detailNote.getContentHash()));
			note.setContentLength(detailNote.getContentLength());
			// add noteContent
			CacheHelper.set_cache_html(note.getGuid(), detailNote.getContent());
			//	add noteText
			String text = StringUtil.parseHTMLtoText(detailNote.getContent());
			List<String> sectionList = new ArrayList<String>();
			int index = GlobalParams.TEXT_SECTION_SIZE;
			int length = text.length();
			while (index<length) {
				sectionList.add(text.substring(index-GlobalParams.TEXT_SECTION_SIZE, index));
				index+=GlobalParams.TEXT_SECTION_SIZE;
			}
			sectionList.add(text.substring(index-GlobalParams.TEXT_SECTION_SIZE));
			CacheHelper.set_cache_text(note.getGuid(), sectionList);
			//	add or update note
			note.setContent(StringUtil.getSubContent(sectionList.get(0), GlobalParams.SIMPLE_CONTENT_SIZE));
			CacheHelper.set_cache(note.getGuid(), note);
			
		} catch (Exception e) {
			LOG.error("updateNoteCache error--->>>", e);
			throw e;
		}
	}
	
	public static void main(String[] args) {
		try {
			CacheHelper.initEhCache(null);
			System.out.println("ray_print-sign-->"+CacheHelper.get_cache(GlobalParams.CACHE_NAME_COUNT_UPDATE));
			if(CacheHelper.get_cache(GlobalParams.CACHE_NAME_LIST_TAG)==null) {
				CacheHelper.set_cache(GlobalParams.CACHE_NAME_LIST_TAG, new ArrayList<String>());
			}
			if(CacheHelper.get_cache(GlobalParams.CACHE_NAME_LIST_NOTEBOOK)==null) {
				CacheHelper.set_cache(GlobalParams.CACHE_NAME_LIST_NOTEBOOK, new ArrayList<String>());
			}
			if(CacheHelper.get_cache(GlobalParams.CACHE_NAME_LIST_NOTE)==null) {
				CacheHelper.set_cache(GlobalParams.CACHE_NAME_LIST_NOTE, new ArrayList<String>());
			}
			CacheHelper.set_cache(GlobalParams.CACHE_NAME_COUNT_UPDATE, 0);
			System.out.println("ray_print-started-->");
			initSyncWithEvernote();
			

			
//			EvernoteAuth evernoteAuth = new EvernoteAuth(EvernoteService.PRODUCTION, GlobalParams.AUTH_TOKEN);
//			ClientFactory factory = new ClientFactory(evernoteAuth);
//			UserStoreClient userStore = factory.createUserStoreClient();
//			NoteStoreClient noteStore = factory.createNoteStoreClient();
//			boolean versionOk = userStore.checkVersion("Evernote EDAMDemo (Java)", com.evernote.edam.userstore.Constants.EDAM_VERSION_MAJOR,
//					com.evernote.edam.userstore.Constants.EDAM_VERSION_MINOR);
//			if (!versionOk) {
//				LOG.error("Incompatible Evernote client protocol version--->>>");
//			} else {
//				List<Notebook> notebooks = noteStore.listNotebooks();
//				for (Notebook notebook : notebooks) {
//					System.out.println("result-->"+notebook.getName()+"-"+notebook.getGuid());
//				}
////				NoteStoreClient noteStore = factory.createNoteStoreClient();
////				SyncState state = noteStore.getSyncState();
////				System.out.println("ray_print-sign-->"+DateToolkit.formatDate(new Date(state.getCurrentTime()), "yyyy-MM-dd HH:mm:ss"));
////				System.out.println("ray_print-sign-->"+DateToolkit.formatDate(new Date(state.getFullSyncBefore()), "yyyy-MM-dd HH:mm:ss"));
////				System.out.println("ray_print-sign-->"+state.getUpdateCount());
////				System.out.println("ray_print-sign-->"+state.getUploaded());
////				SyncChunkFilter filter = new SyncChunkFilter();
////				filter.setIncludeNotes(true);
////				filter.setIncludeNoteResources(true);
////				filter.setIncludeNoteAttributes(true);
////				filter.setIncludeNotebooks(true);
////				filter.setIncludeTags(true);
////				filter.setIncludeResources(true);
////				SyncChunk chunk = noteStore.getFilteredSyncChunk(78, Integer.MAX_VALUE, filter);
////				System.out.println("ray_print-chunk-->"+DateToolkit.formatDate(new Date(chunk.getCurrentTime()), "yyyy-MM-dd HH:mm:ss"));
////				System.out.println("ray_print-chunk-->"+chunk.getChunkHighUSN());
////				System.out.println("ray_print-chunk-->"+chunk.getUpdateCount());
////				System.out.println("ray_print-chunk-->"+chunk.getNotesSize());
////				System.out.println("ray_print-chunk-->"+chunk.getNotebooksSize());
////				System.out.println("ray_print-chunk-->"+chunk.getTagsSize());
//			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
}
